/*
 * $Id: io.c 7557b5d4d82b 2012/12/02 09:07:16 pgurumur $
 *
 * Copyright (c) 2006, 2007, 2008 Prabhu Gurumurthy <pgurumur@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "util.h"

void
set_nonblock()
{ 
   if (dclient->sockfd) {
      int val = fcntl(dclient->sockfd, F_GETFL);
      if (val < 0)
         error("%s fcntl(fd, F_GETFL)", __func__);

      if (val & O_NONBLOCK)
         warning("socket already set to nonblocking");
      else {
         val |= O_NONBLOCK;
         if (fcntl(dclient->sockfd, F_SETFL, val) < 0)
            error("%s fcntl(fd, F_SETFL)", __func__);
      }
   }
}

void
unset_nonblock()
{
   if (dclient->sockfd) {
      int val = fcntl(dclient->sockfd, F_GETFL);
      if (val < 0)
         error("%s fcntl(fd, F_GETFL)", __func__);

      if (!(val & O_NONBLOCK))
         warning("socket is already set to blocking");
      else {
         val &= ~O_NONBLOCK;
         if (fcntl(dclient->sockfd, F_SETFL, val) < 0)
            error("%s fcntl(fd, F_SETFL)", __func__);
      }
   }
}

void 
sock_write(const char *write_buffer)
{
   if (dclient->conn) {
      if (write_buffer) {
         struct pollfd pfd[1];
         int nfds = 0;
         int write_bytes = 0;

         pfd[0].fd = dclient->sockfd;
         pfd[0].events = POLLOUT;

         nfds = poll(pfd, 1, 60 * 100);
         if ((nfds == -1) || (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)))
            error("%s poll()", __func__);

         if (nfds == 0)
            error("%s poll(): timeout", __func__);
         write_bytes = write(
               dclient->sockfd, write_buffer, strlen(write_buffer));
         if (write_bytes < 0)
            error("%s write()", __func__);

         sock_read();
      }
   }
   else
      warning("attempt to write to unconnected socket");
}

void
sock_read()
{
   if (dclient->conn) {
      char buf[CMDLINE_BUF];
      struct pollfd pfd[1];
      int nfds = 0;
      int length = 0;

      pfd[0].fd = dclient->sockfd;
      pfd[0].events = POLLIN;

      boolean flag = TRUE;
      while (flag) {
         nfds = poll(pfd, 1, 1 * 1000);
         if (nfds == 0) {
            flag = FALSE;
         }
         else {
            if ((nfds == -1) || (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)))
               error("%s poll()", __func__);

            length = read(dclient->sockfd, buf, sizeof(buf));
            if (length < 0)
               error("%s read()", __func__);

            if (length > 0) {
               int wr_length = write(fileno(stdout), buf, length);
               if (wr_length < 0)
                  error("%s write()", __func__);
            }
         }

         if (conn_quit) {
            dclient->conn = 0;
            flag = FALSE;
         }

         if ((length == 0) && (!flag))
            flag = TRUE;
      }
   }
   else
      warning("attempt to read from unconnected socket");
}
